#include "IdeaopticsSpectroMeter.h"
#include "SpectrometerConstants.h"
#include <QDebug>

Ideaoptics::ChannelStatus* IdeaopticsSpectroMeter::m_chStatus = nullptr;
int IdeaopticsSpectroMeter::m_chNum = 0;
IdeaopticsSpectroMeter::IdeaopticsSpectroMeter()
{

}

IdeaopticsSpectroMeter::~IdeaopticsSpectroMeter()
{
    CloseSpectro();
}

void IdeaopticsSpectroMeter::SetOtherConfig(QJsonObject config)
{
    _measParam.integrationTime=config["IntegrationTime"].toDouble();
    _measParam.integrationDelay=config["IntegrationDelay"].toDouble();
    _measParam.NrAverages=config["AverageTimes"].toInt();
    // triggerMode需与Ideaoptics::AcquisitionMode匹配，triggerSource不再使用
    _measParam.triggerMode=2;
    _measParam.triggerSource=0;

    _serial=config["Serial"].toString();
    _byteArray = _serial.toUtf8();
    _sn = _byteArray.constData();
    _pcIP = config["PCIP"].toString();
    _pcPort = config["PCPort"].toInt();
    _spectrometerIP = config["SpectrometerIP"].toString();
    _spectrometerPort = config["SpectrometerPort"].toInt();
}

bool IdeaopticsSpectroMeter::InitComm()
{
    return true;
}

bool IdeaopticsSpectroMeter::EnumSpectro(QList<AvsInfo> &listAvsInfo)
{
    bool isSuccessed = true;

    //网卡发现，第一个参数可设置为PC网卡的IP
    m_chNum = Ideaoptics::UpdateDeviceList(nullptr, nullptr);
    m_chStatus = new Ideaoptics::ChannelStatus[m_chNum];
    //获取设备列表
    m_chNum = Ideaoptics::GetDeviceList(m_chStatus);

    for(int i = 0; i < m_chNum; i++)
    {
        AvsInfo sTempDeviceInfo = AvsInfo();
        sTempDeviceInfo.serial = QString(m_chStatus[i].SerialNumber);
        sTempDeviceInfo.pcIP = QString(m_chStatus[i].Info.PCIP);
        sTempDeviceInfo.pcPort = m_chStatus[i].Info.PCPort;
        sTempDeviceInfo.spectrometerIP = QString(m_chStatus[i].Info.SpectrometerIP);
        sTempDeviceInfo.spectrometerPort = m_chStatus[i].Info.SpectrometerPort;

        //根据需要修改status的值
        switch(m_chStatus[i].Status)
        {
        case Ideaoptics::ConnectionStatus::Connected:
            sTempDeviceInfo.status = 'c';
            break;
        case Ideaoptics::ConnectionStatus::Online:
            sTempDeviceInfo.status = 'o';
            break;
        case Ideaoptics::ConnectionStatus::Unavailable:
            sTempDeviceInfo.status = 'u';
            break;
        default:
            break;
        }
        listAvsInfo.append(sTempDeviceInfo);//更新到输出listAvsInfo
    }
    isSuccessed = true;
    return isSuccessed;
}

bool IdeaopticsSpectroMeter::OpenSpectro()
{
    qDebug()<<__FUNCTION__<<__LINE__;

    auto snList = new char*[1];
    snList[0] = new char[Ideaoptics::SERIAL_NUM_LENGTH];
    strcpy_s(snList[0],  Ideaoptics::SERIAL_NUM_LENGTH, _serial.toStdString().c_str());

    int errMsgLen = 128;
    char* errMsg = new char[errMsgLen];
    m_dev = Ideaoptics::GetSpectrometerBySN(snList, 1, errMsg, errMsgLen);
    if (m_dev == nullptr)
    {
        qDebug()<<__FUNCTION__<<__LINE__<< "Opening device failed!";
        delete[] errMsg;
        errMsg = nullptr;
        return false;
    }
    delete[] errMsg;
    errMsg = nullptr;
    delete[] snList[0];
    delete[] snList;

    // 连接光谱仪
    if (!Ideaoptics::Connect(m_dev))
    {
        Ideaoptics::FreeSpectrometer(m_dev);
        return false;
    }

    GetLambda();
    // 注册光谱事件回调函数
    Ideaoptics::RegisterPushedSpectrumOfOneChannelReceivedCallback(m_dev, &IdeaopticsSpectroMeter::OnPushedSpectrumOfOneChannelReceived, this);

    return true;
}

bool IdeaopticsSpectroMeter::CloseSpectro()
{
    // 注销光谱事件回调函数
    Ideaoptics::UnregisterPushedSpectrumOfEachChannelReceivedCallback(m_dev);
    // 断开连接
    Ideaoptics::Disconnect(m_dev);
    // 释放光谱仪对象
    Ideaoptics::FreeSpectrometer(m_dev);
    m_dev = nullptr;
    return true;
}

bool IdeaopticsSpectroMeter::SetMeasureParam(AvsMeasPara param)
{
    memcpy(&_measParam, &param, sizeof(AvsMeasPara));
    bool ret = true;
    //设置可调增益(第三个参数是是否写入flash以实现掉电保存)
    ret = Ideaoptics::SetSignalGainOfSn(m_dev, _sn, false, _measParam.gain[0]);
    //设置积分时间
    ret &= Ideaoptics::SetIntegrationTimeOfSn(m_dev, _sn, _measParam.integrationTime);
    //设置平均次数
    ret &= Ideaoptics::SetAverageOfSn(m_dev, _sn, _measParam.NrAverages);
    //设置触发延时（请关注是否符合需求，本接口所接受的延时时间单位是毫秒）
    ret &= Ideaoptics::SetTriggerDelayOfSn(m_dev, _sn, _measParam.integrationDelay);
    //设置触发模式
    Ideaoptics::AcquisitionMode mode = Ideaoptics::AcquisitionMode::FreeRun;
    //todo:根据触发模式选择合适的AcquisitionMode
    //FreeRun: Ideaoptics::AcquisitionMode::FreeRun
    //软件触发单帧： Ideaoptics::AcquisitionMode::SoftwareTriggerSingleFrame
    //外部上升沿触发。上升沿触发单帧采集： Ideaoptics::AcquisitionMode::RisingEdgeTriggerSingleFrame
    //其他触发模式见SDK说明 Ideaoptics::AcquisitionMode
    if (_measParam.triggerMode == 0)
    {
        mode = Ideaoptics::AcquisitionMode::SoftwareTriggerSingleFrame;
    }
    else if (_measParam.triggerMode == 1)
    {
        mode = Ideaoptics::AcquisitionMode::RisingEdgeTriggerSingleFrame;
    }
    else if (_measParam.triggerMode == 2)
    {
        mode = Ideaoptics::AcquisitionMode::FreeRun;
    }
    //设置触发次数
    unsigned short n = 0;
    ret &= Ideaoptics::SetTriggerModeOfSn(m_dev, _sn, mode, n);
    if(ret)
    {
        return true;
    }
    else
    {
        qDebug()<<__FUNCTION__<<__LINE__<<"光谱仪参数设置失败!";
        return false;
    }
}

bool IdeaopticsSpectroMeter::GetMeasParam(AvsMeasPara &measConfigParam)
{
    bool ret = true;
    //读取积分时间
    double intTime;
    ret &= Ideaoptics::GetIntegrationTimeOfSn(m_dev, _sn, intTime);
    _measParam.integrationTime=static_cast<float>(intTime);
    int avgNum;
    ret &= Ideaoptics::GetAverageOfSn(m_dev, _sn, avgNum);
    _measParam.NrAverages=avgNum;
    //读取触发模式和触发帧数
    auto mode = Ideaoptics::AcquisitionMode::FreeRun;
    unsigned short frames = 0;
    ret &= Ideaoptics::GetTriggerModeOfSn(m_dev, _sn, &mode, &frames);
    //同理根据AcquisitionMode匹配对应的触发模式
    if (mode == Ideaoptics::AcquisitionMode::SoftwareTriggerSingleFrame)
    {
        _measParam.triggerMode=0;
        //_measParam.triggerSource=略
    }
    else if (mode == Ideaoptics::AcquisitionMode::RisingEdgeTriggerSingleFrame)
    {
        _measParam.triggerMode=1;
    }
    else if (mode == Ideaoptics::AcquisitionMode::FreeRun)
    {
        _measParam.triggerMode=2;
    }
    //读取触发延时
    double delay;
    ret &= Ideaoptics::GetTriggerDelayOfSn(m_dev, _sn, delay);
    _measParam.integrationDelay=delay;
    //读取可调增益(第三个参数是是否从flash中读取)
    double gain;
    ret &= Ideaoptics::GetSignalGainOfSn(m_dev, _sn, false, gain);
    _measParam.gain[0]=gain;
    _measParam.gain[1]=0;
    measConfigParam=_measParam;

    return ret;
}

const QList<double> IdeaopticsSpectroMeter::GetLambda()
{
    if(_lambda.empty())
    {
        int NumPixels = Ideaoptics::GetPixelNumberOfOneChannel(m_dev);
        double *dLambda=new double[NumPixels];
        //成功:波长数据长度; 失败:-1
        int ret = Ideaoptics::GetWavelengthOfSn(m_dev, _sn, dLambda, NumPixels);
        for(int i=0;i<NumPixels;i++)
        {
            _lambda.append(dLambda[i]);
        }
    }
    return _lambda;
}

bool IdeaopticsSpectroMeter::StartMeasure()
{
    AvsMeasPara para;
    //GetMeasParam(para);
    return Ideaoptics::EnableSpectrumPushingOfSn(m_dev, _sn);
}

bool IdeaopticsSpectroMeter::Stop()
{
    return Ideaoptics::DisableSpectrumPushingOfSn(m_dev, _sn);
}

// 光谱事件回调函数
void IdeaopticsSpectroMeter::OnPushedSpectrumOfOneChannelReceived(Ideaoptics::IMultiChannelSpectrometer* dev, char* sn, Ideaoptics::SpectrumDataClr* data, void* userData)
{
    //qDebug()<<__FUNCTION__<<__LINE__<<QDateTime::currentDateTime().toString("hh:mm:ss.zzz")<<" 光谱仪接收到数据!";
    auto parent = (IdeaopticsSpectroMeter*)userData;
    emit parent->ReceiveDataIsHere(data);
}

void IdeaopticsSpectroMeter::ReceiveDataIsHere(Ideaoptics::SpectrumDataClr* data)
{
    //这两步非常重要,线程同步工具
    static QMutex _mutex;
    QMutexLocker locker(&_mutex);
    //    qDebug()<<__FUNCTION__<<__LINE__<<device;
    QList<QPointF> ret;

    double yMin = 70000;
    double yMax = -1;
    int length = data->GetLength();
    for(int i = 0; i < length; i++)
    {
        auto curVal = data->Spectrum[i];
        if(curVal > yMax)
        {
            yMax = curVal;
        }
        else if(curVal < yMin)
        {
            yMin = curVal;
        }
        ret.append(QPointF(_lambda.at(i),curVal));
    }
    AvsMeasResult sendData;
    sendData.SerialId=_serial;
    sendData.resultData=ret;
    emit OnDataReceive(sendData);
}

SpectroInfoTag IdeaopticsSpectroMeter::GetSpectrumInfo()
{
    //    qDebug()<<__FUNCTION__<<__LINE__<<GetLambda().count();
    SpectroInfoTag ret(GetLambda());
    ret.serilID=_serial;
    return ret;
}

bool IdeaopticsSpectroMeter::SoftTrigger()
{
    return Ideaoptics::SoftTriggerOfSn(m_dev, _sn);
}
